package com.yingjia.yingjiauniversity.retrofit.request;

import android.os.Looper;

import com.yingjia.yingjiauniversity.retrofit.HttpLogger;
import com.yingjia.yingjiauniversity.retrofit.convert.ChunkingConverterFactory;
import com.yingjia.yingjiauniversity.retrofit.convert.CommonJsonConverterFactory;
import com.yingjia.yingjiauniversity.retrofit.preference.Preference;
import com.yingjia.yingjiauniversity.retrofit.progress.ProgressListener;
import com.yingjia.yingjiauniversity.retrofit.progress.ProgressResponseBody;
import com.yingjia.yingjiauniversity.utils.StringUtil;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * Created by 张智轶 on 2016/10/9.
 */
public class RequestBuilder {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private static final long CONNECT_DEFAULT_TIMEOUT = 10;
    private static final long WRITE_DEFAULT_TIMEOUT = 30;
    private static final long READ_DEFAULT_TIMEOUT = 30;

    private static Retrofit.Builder defaultBuilder = createRetrofitBuilder();
    private static OkHttpClient.Builder defaultClientBuilder = createClientBuilder();
    private static Retrofit.Builder gsonConverBuilder = null;

    private Retrofit.Builder builder = null;

    private OkHttpClient.Builder clientBuilder = null;

    public RequestBuilder url(String url) {
        if (builder == null) {
            builder = createRetrofitBuilder();
        }
        builder.baseUrl(url);
        return this;
    }

    public RequestBuilder() {
    }

    public RequestBuilder(Converter.Factory factory) {
        if (gsonConverBuilder == null) {
            gsonConverBuilder = createGsonConverRetrofitBuilder(factory);
        }
    }

    public <T> T download(Class<T> clazz, final ProgressListener progressListener) {

        ifNullSetBuilder();

        clientBuilder = new OkHttpClient.Builder()
                .addNetworkInterceptor(new Interceptor() {
                    @Override
                    public Response intercept(Chain chain) throws IOException {
                        Response orginalResponse = chain.proceed(chain.request());
                        return orginalResponse.newBuilder()
                                .body(new ProgressResponseBody(orginalResponse.body(), new ProgressListener() {
                                    @Override
                                    public void onProgress(long progress, long total, boolean done) {
                                        logger.info(Looper.myLooper() + "");
                                        logger.info("onProgress: " + "total ---->" + total + ",done ---->" + progress);
                                        progressListener.onProgress(progress, total, done);
                                    }
                                }))
                                .build();
                    }
                });
        OkHttpClient client = clientBuilder.build();
        builder.client(client);

        Retrofit retrofit = builder.build();
        T repo = retrofit.create(clazz);
        return repo;
    }

    /**
     * <构建retrofit的json请求>
     *
     * @param <T>   the type parameter
     * @param clazz the clazz
     * @return the t
     * @author: zhoubing
     * @date: 2017-12-29 23:07:43
     * @version: v1.0
     */
    public <T> T json(Class<T> clazz) {

        ifNullSetBuilder();

        OkHttpClient httpClient = clientBuilder.build();
        builder.client(httpClient);

        Retrofit retrofit = builder.build();
        T repo = retrofit.create(clazz);
        return repo;
    }

    public <T> T gjson(Class<T> clazz) {
        //如果设置的url为空， 从全局配置中获取url
        setDefaultUrl(gsonConverBuilder);

        if (clientBuilder == null) {
            clientBuilder = defaultClientBuilder;
        }

        OkHttpClient httpClient = clientBuilder.build();
        gsonConverBuilder.client(httpClient);

        Retrofit retrofit = gsonConverBuilder.build();
        T repo = retrofit.create(clazz);
        return repo;
    }


    public <T> T upload(Class<T> clazz, final ProgressListener progressListener, RequestBody requestBody) {

        ifNullSetBuilder();

        Retrofit.Builder builder = new Retrofit.Builder();

        T repo = builder.addConverterFactory(new ChunkingConverterFactory(requestBody, new ProgressListener() {
            @Override
            public void onProgress(long progress, long total, boolean done) {
                logger.debug("onProgress: " + "total ---->" + total + ",done ---->" + progress);
                logger.debug("onProgress: " + "total ---->" + total + ",done ---->" + progress);
                progressListener.onProgress(progress, total, done);
            }
        })).addConverterFactory(GsonConverterFactory.create()).build().create(clazz);
        return repo;
    }


    /**
     * <测试使用, 通过mock response模拟接口>
     *
     * @param url      the url
     * @param jsonResp the json resp
     * @author: guoxiangxun
     * @date: Sep 12, 2017 1:17:53 PM
     * @version: v1.0
     */
    public static void addMockJsonResponse(final String url, final String jsonResp) {

        Interceptor mockInterceptor = new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Response response = null;
                Response.Builder responseBuilder = new Response.Builder()
                        .code(200)
                        .message("")
                        .request(chain.request())
                        .protocol(Protocol.HTTP_1_0)
                        .addHeader("content-type", "application/json");
                Request request = chain.request();

                if (request.url().toString().startsWith(url)) { //拦截指定地址
                    String responseString = jsonResp;    //模拟数据返回body
                    responseBuilder.body(ResponseBody.create(MediaType.parse("application/json"), responseString.getBytes()));//将数据设置到body中
                    response = responseBuilder.build(); //builder模式构建response
                } else {
                    response = chain.proceed(request);
                }
                return response;
            }
        };

        RequestBuilder.defaultClientBuilder.addInterceptor(mockInterceptor);
    }

    /**
     * add mock interceptor
     *
     * @param mockInterceptor
     */
    public static void addMockInterceptor(Interceptor mockInterceptor) {
        RequestBuilder.defaultClientBuilder.addInterceptor(mockInterceptor);
    }

    /***********************************
     * 内部方法
     **********************************/


    private static Retrofit.Builder createRetrofitBuilder() {
        Retrofit.Builder b = new Retrofit.Builder()
                .addConverterFactory(CommonJsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create());

        return b;
    }

    private static Retrofit.Builder createGsonConverRetrofitBuilder(Converter.Factory factory) {
        Retrofit.Builder b = new Retrofit.Builder()
                .addConverterFactory(factory)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create());

        return b;
    }

    private static void setDefaultUrl(Retrofit.Builder b) {
        String url = Preference.getValue(Preference.BASE_URL);

        if (!StringUtil.isEmpty(url)) {
            b.baseUrl(url);
        } else {
            //avoid empty throw exception.
            b.baseUrl("http://0.0.0.0");
        }
    }


    private static OkHttpClient.Builder createClientBuilder() {
        //设置连接超时,retrofit默认三个超时都是10秒
        return new OkHttpClient.Builder()
                .addInterceptor(HttpLogger.create())
                .connectTimeout(CONNECT_DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .writeTimeout(WRITE_DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(READ_DEFAULT_TIMEOUT, TimeUnit.SECONDS);
    }

    /**
     * <如果为空设置默认的builder>
     *
     * @author: guoxiangxun
     * @date: Jun 5, 2016 6:30:54 PM
     * @version: v1.0
     */
    private void ifNullSetBuilder() {
        //如果设置的url为空， 从全局配置中获取url
        if (builder == null) {
            builder = defaultBuilder;
            setDefaultUrl(builder);
        }

        if (clientBuilder == null) {
            clientBuilder = defaultClientBuilder;
        }
    }
}
